<?php

class ControllerBase extends Logger {

  protected static $_instance = null;

  public static function getInstance(){
    if(null !== static::$_instance){
      return static::$_instance;
    }
    static::$_instance = new static();
    return static::$_instance;
  }

  private function  __construct() {
    $this->user = User::getInstance();

  }

  private function  __clone() { }
  
  public function dispatch($uri, $get, $post){
    try{


      Config::setDefault("base_path", dirname($_SERVER['SCRIPT_FILENAME']).'/app/');
      $this->getParameters = $get;
      $this->postParameters = $post;
      $this->useURLParameters($uri);
      $this->urlParametersString = $this->pureURI($uri);

      $this->parameters = array_merge($this->urlParametersAssoc, $get, $post);

      $this->executeAction();
      return $this;


    } catch(Exception $e){
      echo('ERROR: ');
      echo('<div id="report_">');
      echo("(".$e->getCode().") ".$e->getMessage()."\n");
      echo($e->getFile());
      echo("(".$e->getLine().")\n<pre>");
      echo($e->getTraceAsString());
      echo($e->getPrevious());
      echo('</pre></div>');
      die();
    }
  }

  public function forward($module, $action){

    $this->module_name = $module;
    $this->action_name = $action;

    $this->executeAction();

    return $this;
  }
  
  public function redirect($url){
    if(Session::get("debug") == true) {
        die('Redireccionando a: <a href="'.$url.'">'.$url.'</a>');
    } else {
        header("Location: " . $url);
        die();
    }
  }

  private function executeAction(){
    if($this->actionExists($this->module_name, $this->action_name)) {
      $module_name = $this->module_name."Actions";
      $this->module = new $module_name;
      $this->module->controller = $this;
      $this->module->user = $this->user;
      $this->module->parameters(array(
          "get" => $this->getParameters,
          "post" => $this->postParameters,
          "url" => $this->urlParametersAssoc,
          "num" => $this->urlParametersNum,
          "all" => $this->parameters,
          "module" => $this->module_name,
          "action" => $this->action_name
          ));
      $action = "page".$this->action_name;
      $this->module->$action();
    } else {
      throw new Exception("No existe la accion ".$this->action_name." en el modulo ".$this->module_name);
    }
  }

  private function pureURI($uri){
    //quita los directorios y parametros GET dejando solo los parametros URL-friendly
    //
    // ej:
    //
    // tanto  http://localhost/path/to/site/index.php/param1/param2/param3?id=15
    // como  http://localhost/path/to/site/param1/param2/param3?id=15 (ocultando el script con mod_rewrite)
    //
    // devuelve:
    //      param1/param2/param3


    $base_url = Config::get("base_url", dirname($_SERVER['SCRIPT_NAME']).'/');
    $frontend_script = basename($_SERVER['SCRIPT_NAME']);
    $alt_base_url =  dirname(dirname($_SERVER['SCRIPT_NAME'])).'/';
    $alt_base_url = str_replace('\\','/',$alt_base_url);

    $this->log("\$base_url.\$frontend_script = " . $base_url.$frontend_script);
    $this->log("\$alt_base_url.\$frontend_script = ".$alt_base_url.$frontend_script);
    $this->log("\$base_url.\$frontend_script = " . $base_url.$frontend_script);
    $this->log("\$alt_base_url.\$frontend_script = " . $alt_base_url.$frontend_script);

    if(strpos($uri,$base_url.$frontend_script) === 0){
      $uri = substr($uri, strlen($base_url.$frontend_script));
    } elseif(strpos($uri,$alt_base_url.$frontend_script) === 0){
      $uri = substr($uri, strlen($alt_base_url.$frontend_script));
    } elseif(strpos($uri,$base_url) === 0){
      $uri = substr($uri, strlen($base_url));
    } elseif(strpos($uri,$alt_base_url) === 0){
      $uri = substr($uri, strlen($alt_base_url));
    }

    if(strpos($uri,"?") > -1){
      $uri = substr($uri, 0, strpos($uri,"?"));
    }

    if(substr($uri, 0, 1) == "/") $uri = substr($uri, 1);

    if(substr($uri, -1) == "/") $uri = substr($uri, 0, -1);

    $this->log('Pure URI: '.$uri);
    return $uri;
  }

  private function useURLParameters($uri){
    $params = $this->parseURLParams($uri);
    $this->urlParametersAssoc = $params['assoc'];
    $this->urlParametersNum = $params['num'];
    $this->module_name = $params['module'];
    $this->action_name = $params['action'];
  }
  public function parseURLParams($uri, $separator = null, $equals = null){
    if(is_null($separator)) $separator = Config::get("params_separator", "/");
    if(is_null($equals)) $equals = Config::get("params_assignment_operator", ":");

    $this->log("URI: ".$uri);
    $uri = $this->pureURI($uri);
    $this->log("URI simplificada: ".$uri);

    $param_pairs = explode($separator, $uri);

    

    $params = array('num' => array(), 'assoc' => array(), 'module' => null, 'action' => null);

    $params['module'] = ($this->moduleExists($param_pairs[0])) ? array_shift($param_pairs) : "default";
    if(!isset($param_pairs[0])) $param_pairs[0] = "default";
    $params['action'] = ($this->actionExists($params['module'], $param_pairs[0])) ? array_shift($param_pairs) : "default";


    foreach($param_pairs as $p){

      $params['num'][] = $p;

      $pair = explode($equals, $p, 2);
      if(strlen($pair[0]) > 0) {
        $params['assoc'][$pair[0]] = (isset($pair[1])?$pair[1]:true);
      }
    }

    if(is_null($params['module'])){
      $params['module'] = Config::get("default_module","default");
    }
    if(is_null($params['action'])){
      $params['action'] = Config::get("default_action","default");
    }

    return $params;
  }

  public function moduleExists($module_name){
    
    $base = Config::get("base_path","/");

    if(strlen($module_name) > 0 && is_dir($base . Config::get("modules_dir","modules")."/".$module_name)) {
      return true;
    } else {
      return false;
    }
  }

  public function actionExists($module_name, $action_name){
    $base = Config::get("base_path","/");

    if($this->moduleExists($module_name)) {
      require_once($base . Config::get("modules_dir","modules")."/".$module_name . "/actions.php");
      return method_exists(ucfirst($module_name)."Actions", "page".ucfirst($action_name));
    } else {
      return false;
    }
  }


}